x86: AMD core-pair topology detection code
authorWei Huang <wei.huang2@amd.com>
Tue, 28 Jun 2011 08:13:53 +0000 (09:13 +0100)
committerWei Huang <wei.huang2@amd.com>
Tue, 28 Jun 2011 08:13:53 +0000 (09:13 +0100)
This patch is to support core-pair topology introduced by AMD CPUs,
which introduces a new concept of [core, compute unit]. There is a new
feature bit for topology extension in CPUID:0x80000001. Also a new
CPUID 0x8000001E is introduced for CPU topology enumeration. This
patch collects the sibling information from the new CPUID and will be
stored in the sibling map in Xen hypervisor.

Signed-off-by: Wei Huang <wei.huang2@amd.com>
xen/arch/x86/cpu/amd.c
xen/arch/x86/cpu/common.c
xen/arch/x86/smpboot.c
xen/include/asm-x86/processor.h

index 9bdee6c238eb37139402b7a0958b2d54add37e0d..386b0c2e387428d4974c2ba2e66f73bd858cf6b0 100644 (file)
@@ -326,6 +326,49 @@ static void check_syscfg_dram_mod_en(void)
        wrmsrl(MSR_K8_SYSCFG, syscfg);
 }
 
+static void __devinit amd_get_topology(struct cpuinfo_x86 *c)
+{
+#ifdef CONFIG_X86_HT
+        int cpu;
+        unsigned bits;
+
+        if (c->x86_max_cores <= 1)
+                return;
+        /*
+         * On a AMD multi core setup the lower bits of the APIC id
+         * distingush the cores.
+         */
+        cpu = smp_processor_id();
+        bits = (cpuid_ecx(0x80000008) >> 12) & 0xf;
+
+        if (bits == 0) {
+                while ((1 << bits) < c->x86_max_cores)
+                        bits++;
+        }
+
+        /* Low order bits define the core id */
+        c->cpu_core_id = c->phys_proc_id & ((1<<bits)-1);
+        /* Convert local APIC ID into the socket ID */
+        c->phys_proc_id >>= bits;
+        /* Collect compute unit ID if available */
+        if (cpu_has(c, X86_FEATURE_TOPOEXT)) {
+                u32 eax, ebx, ecx, edx;
+
+                cpuid(0x8000001e, &eax, &ebx, &ecx, &edx);
+                c->compute_unit_id = ebx & 0xFF;
+                c->x86_num_siblings = ((ebx >> 8) & 0x3) + 1;
+        }
+        
+        if (opt_cpu_info)
+                printk("CPU %d(%d) -> Processor %d, %s %d\n",
+                       cpu, c->x86_max_cores, c->phys_proc_id,
+                       cpu_has(c, X86_FEATURE_TOPOEXT) ? "Compute Unit" : 
+                                                         "Core",
+                       cpu_has(c, X86_FEATURE_TOPOEXT) ? c->compute_unit_id :
+                                                         c->cpu_core_id);
+#endif
+}
+
 static void __devinit init_amd(struct cpuinfo_x86 *c)
 {
        u32 l, h;
@@ -433,26 +476,7 @@ static void __devinit init_amd(struct cpuinfo_x86 *c)
                }
        }
 
-#ifdef CONFIG_X86_HT
-       /*
-        * On a AMD multi core setup the lower bits of the APIC id
-        * distingush the cores.
-        */
-       if (c->x86_max_cores > 1) {
-               int cpu = smp_processor_id();
-               unsigned bits = (cpuid_ecx(0x80000008) >> 12) & 0xf;
-
-               if (bits == 0) {
-                       while ((1 << bits) < c->x86_max_cores)
-                               bits++;
-               }
-               c->cpu_core_id = c->phys_proc_id & ((1<<bits)-1);
-               c->phys_proc_id >>= bits;
-               if (opt_cpu_info)
-                       printk("CPU %d(%d) -> Core %d\n",
-                              cpu, c->x86_max_cores, c->cpu_core_id);
-       }
-#endif
+        amd_get_topology(c);
 
        /* Pointless to use MWAIT on Family10 as it does not deep sleep. */
        if (c->x86 >= 0x10 && !force_mwait)
index 0b6b3b11d1358e8f8b611977e991703de6789d27..4cdf289d78843583f5408924c3d0696c11514d1d 100644 (file)
@@ -318,6 +318,7 @@ void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
        c->x86_clflush_size = 0;
        c->phys_proc_id = BAD_APICID;
        c->cpu_core_id = BAD_APICID;
+       c->compute_unit_id = BAD_APICID;
        memset(&c->x86_capability, 0, sizeof c->x86_capability);
 
        generic_identify(c);
index 6f48a404430dc4a013979fd8c36a7303c26e0f30..ccf1c0e5ca09f0924ebba1981e380f65fb056c7c 100644 (file)
@@ -230,6 +230,14 @@ static int booting_cpu;
 /* CPUs for which sibling maps can be computed. */
 static cpumask_t cpu_sibling_setup_map;
 
+static void link_thread_siblings(int cpu1, int cpu2)
+{
+    cpu_set(cpu1, per_cpu(cpu_sibling_map, cpu2));
+    cpu_set(cpu2, per_cpu(cpu_sibling_map, cpu1));
+    cpu_set(cpu1, per_cpu(cpu_core_map, cpu2));
+    cpu_set(cpu2, per_cpu(cpu_core_map, cpu1));
+}
+
 static void set_cpu_sibling_map(int cpu)
 {
     int i;
@@ -241,13 +249,13 @@ static void set_cpu_sibling_map(int cpu)
     {
         for_each_cpu_mask ( i, cpu_sibling_setup_map )
         {
-            if ( (c[cpu].phys_proc_id == c[i].phys_proc_id) &&
-                 (c[cpu].cpu_core_id == c[i].cpu_core_id) )
-            {
-                cpu_set(i, per_cpu(cpu_sibling_map, cpu));
-                cpu_set(cpu, per_cpu(cpu_sibling_map, i));
-                cpu_set(i, per_cpu(cpu_core_map, cpu));
-                cpu_set(cpu, per_cpu(cpu_core_map, i));
+            if ( cpu_has(c, X86_FEATURE_TOPOEXT) ) {
+                if ( (c[cpu].phys_proc_id == c[i].phys_proc_id) &&
+                     (c[cpu].compute_unit_id == c[i].compute_unit_id) )
+                    link_thread_siblings(cpu, i);
+            } else if ( (c[cpu].phys_proc_id == c[i].phys_proc_id) &&
+                        (c[cpu].cpu_core_id == c[i].cpu_core_id) ) {
+                link_thread_siblings(cpu, i);
             }
         }
     }
@@ -828,6 +836,7 @@ remove_siblinginfo(int cpu)
     cpus_clear(per_cpu(cpu_core_map, cpu));
     c[cpu].phys_proc_id = BAD_APICID;
     c[cpu].cpu_core_id = BAD_APICID;
+    c[cpu].compute_unit_id = BAD_APICID;
     cpu_clear(cpu, cpu_sibling_setup_map);
 }
 
index 57923d66ca941352b100246d5c2ea389c07dd122..ae880e807d530fc5d47f6577913a24c2428d5b56 100644 (file)
@@ -175,9 +175,10 @@ struct cpuinfo_x86 {
     __u32 x86_max_cores; /* cpuid returned max cores value */
     __u32 booted_cores;  /* number of cores as seen by OS */
     __u32 x86_num_siblings; /* cpuid logical cpus per chip value */
+    __u32 apicid;
     int   phys_proc_id; /* package ID of each logical CPU */
     int   cpu_core_id; /* core ID of each logical CPU*/
-    __u32 apicid;
+    int   compute_unit_id; /* AMD compute unit ID of each logical CPU */
     unsigned short x86_clflush_size;
 } __cacheline_aligned;